<?php

use PhpOffice\PhpWord\Element\Section;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Style\Indentation;
use PhpOffice\PhpWord\Style\Table as TableStyle;

/**
 * word导出类
 */
class Word
{
    /**
     * phpword实例
     * @var PhpWord
     */
    protected static PhpWord $phpWord;
    /**
     * phpword--section
     * @var Section
     */
    protected static Section $section;
    /**
     * 段落的行高
     * @var int|float
     */
    protected static int|float $wordLineHeight = 1.5;
    /**
     * 内容文本对齐方式
     * @var string
     */
    protected static string $wordTextAlign = 'left';
    /**
     * 段落首行缩进字数
     * @var int
     */
    protected static int $wordTabNumber = 2;
    /**
     * 页面样式
     * @var array|int[]
     */
    protected static array $sectionStyle = [
        'marginLeft' => 300,
        'marginRight' => 300,
        'marginTop' => 300,
        'marginBottom' => 400];
    /**
     * 标题样式
     * @var array|string[]
     */
    protected static array $titleStyle = [
        // 字体
        'name' => '宋体',
        // 大小
        'size' => ''
    ];
    /**
     * 标题段落样式
     * @var array|string[]
     */
    protected static array $titlePstyle = [
        // 对齐方式
        'align' => 'center'
    ];
    /**
     * 内容文本眼样式
     * @var array
     */
    protected static array $textStyle = [
        // 字体
        'name' => '宋体',
        // 字体大小
        'size' => 13
    ];
    /**
     * 表格样式
     * @var array
     */
    protected static array $tableStyle = [
        // 边框颜色
        'borderColor' => "#154187",
        // 边框宽度
        'borderSize' => 10,
        // 单元格上边距
        'cellMarginTop' => 200,
        // 单元格下边距
        'cellMarginBottom' => 200,
        // 表格布局  fixed固定大小
        'layout' => TableStyle::LAYOUT_FIXED,
    ];
    /**
     * 表格单元格默认宽度
     * @var int
     */
    protected static int $tableTotalWidth = 11400;

    /**
     * 初始化
     */
    private static function init(): void
    {
        // 初始化phpword
        self::initPhpWord();
        // 创建section
        self::createSection();
    }

    /**
     * 导出
     * @param $data
     * @param string $fName
     * @return void
     */
    public static function export($data, string $fName = ''): void
    {
        self::init();

        self::handleData($data);

        if (empty($fName)) $fName = date('YmdHis') . '文档';

        self::outPut($fName);
    }

    /**
     * 处理数据
     * @param $data
     * @return void
     */
    private static function handleData($data): void
    {
        foreach ($data as $item) {
            switch ($item['type']) {
                case 'title':
                    // 添加标题
                    self::addTitle($item['data']);
                    break;
                case 'text':
                    // 处理文字
                    self::handleText($item['data']);
                    break;
                case 'table':
                    self::handleTable($item['data']);
                    break;
            }
            //添加换行符
            self::addBreak();
        }
    }

    /**
     * 实例化phpword
     * @return void
     */
    private static function initPhpWord(): void
    {
        self::$phpWord = new PhpWord(); //实例化
    }


    /**
     * 设置phpwordsection
     * @return void
     */
    private static function createSection(): void
    {
        self::$section = self::$phpWord->addSection(self::$sectionStyle);
    }


    /**
     * 添加phpword标题
     * @param $title
     * @param int $size
     * @return void
     */
    private static function addTitle($title, int $size = 40): void
    {
        self::$titleStyle['size'] = $size;
        self::$section->addText(
            $title,
            self::$titleStyle,
            self::$titlePstyle,
        );
    }

    /**
     * 添加换行
     * @param int $line
     * @return void
     */
    private static function addBreak(int $line = 2): void
    {
        self::$section->addTextBreak($line);
    }


    /**
     * 处理文字
     * @param $data
     * @return void
     */
    private static function handleText($data): void
    {
        foreach ($data as $item) {
            if ($item['tab']) {
                self::insertTabText($item['content']);
            } else {
                self::insertText($item['content']);
            }
            //添加换行符
            self::addBreak();
        }
    }

    /**
     * 处理表格数据
     * @param $data
     * @return void
     */
    private static function handleTable($data): void
    {
        $table = self::$section->addTable(self::$tableStyle);

        foreach ($data as $item) {
            if (isset($item['cellSpan']) && $item['cellSpan']) {
                self::createCellSpan($table, $item['cell']);
            } elseif (isset($item['rowSpan']) && $item['rowSpan']) {
                self::createRowSpan($table, $item['cell']);
            } else {
                self::createCell($table, $item['cell']);
            }
        }
    }

    /**
     * 添加含有跨列的单元格
     * @param Table $table
     * @param $cellData
     * @return void
     */
    private static function createCellSpan(Table $table, $cellData): void
    {
        $table->addRow();
        $cellWidth = self::getDefaultWidth($cellData);

        foreach ($cellData as $item) {
            $pstyle = self::getPstyle($item);

            if (is_array($item)) {
                $cellWidth = self::getWidth($item) ?? $cellWidth;

                if (isset($item['span']) && (int)$item['span'] > 0) {
                    $cell = $table->addCell($cellWidth);
                    $cell->addText($item['content']);
                    $cell->getStyle()->setGridSpan((int)$item['span']);
                } else {
                    $table->addCell($cellWidth, $pstyle)->addText($item['content']);
                }

            } else {
                $table->addCell($cellWidth, $pstyle)->addText($item);
            }
        }

    }

    /**
     * 添加跨行的单元格
     * @param Table $table
     * @param $cellData
     * @return void
     */
    private static function createRowSpan(Table $table, $cellData): void
    {
        $table->addRow();

        // 默认宽度
        $cellWidth = self::getDefaultWidth($cellData);
        foreach ($cellData as $cell) {
            if (is_array($cell)) {
                $cellWidth = self::getWidth($cell) ?? $cellWidth;
                $cell = $cell['content'];
            }
            self::insertRowSpan($table, $cell, $cellWidth);

        }
    }

    /**
     *插入跨行单元格
     * */
    private static function insertRowSpan($table, $cell, $cellWidth): void
    {
        // 跨行样式,用于显示文字
        $cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'width' => $cellWidth);
        // 跨行无连接线,用于填补空行
        $cellRowContinue = array('vMerge' => 'continue', 'width' => $cellWidth);
        if (empty($cell)) {
            $table->addCell($cellWidth, $cellRowContinue);
        } else {
            $table->addCell($cellWidth, $cellRowSpan)->addText($cell);
        }
    }

    /**
     * 创建普通单元格
     * @param Table $table
     * @param array $cellData
     * @return void
     */
    private static function createCell(Table $table, array $cellData): void
    {
        $table->addRow();
        // 获取默认宽度
        $cellWidth = self::getDefaultWidth($cellData);
        foreach ($cellData as $key => $item) {
            // 段落格式
            $pstyle = self::getPstyle($item);
            if (is_array($item)) {
                $pstyle = self::getPstyle($item);
                $cellWidth = self::getWidth($item) ?? $cellWidth;

                $item = $item['content'];

            }
            $table->addCell($cellWidth, $pstyle)->addText($item);
        }
    }

    /**
     * 根据列数获取宽度
     * @param $cellData
     * @return int
     */
    private static function getDefaultWidth($cellData): int
    {
        // 计算宽度
        $totalWidth = self::$tableTotalWidth;
        // 默认根据列数平均分
        return (int)bcdiv((string)$totalWidth, (string)count($cellData));
    }

    /**
     * 获取自定义宽度
     * @param $item
     * @return int|string
     */
    private static function getWidth($item): int|string
    {
        $width = '';
        if (isset($item['width']) && (int)$item['width'] > 0) {
            $width = (int)$item['width'];
        }
        return $width;
    }


    /**
     * 获取表格自定义格式
     * @param $item
     * @return array
     */
    private static function getPstyle($item): array
    {
        $style = [];
        $style_key = ['bgColor', 'borderColor', 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor', 'borderSize', 'borderTopSize', 'borderRightSize', 'borderBottomSize', 'borderLeftSize', 'valign'];
        if (is_array($item)) {
            foreach ($item as $key => $items) {
                if (in_array($key, $style_key)) {
                    $style[$key] = $items;
                }
            }
        }
        return $style;
    }


    /**
     * 插入首行缩进的段落
     * @param $text
     * @return void
     */
    private static function insertTabText($text): void
    {
        // 段落样式
        $pstyle = self::wordPstyle();
        // 添加文本
        self::$section->addText(
            $text,
            self::$textStyle,
            $pstyle
        );
    }

    /**
     * 插入普通的段落
     * @param $text
     * @return void
     */
    private static function insertText($text): void
    {
        // 添加文本
        self::$section->addText(
            $text,
            self::$textStyle,
            ['lineHeight' => self::$wordLineHeight, 'align' => self::$wordTextAlign]
        );
    }

    /**
     * 获取首行缩进的基础段落样式
     * @return array
     */
    private static function wordPstyle(): array
    {
        // 首行缩进
        $Indent_m = new Indentation();
        // 设置首行缩进2*16字体字符
        $Indent_m->setFirstLine(self::$wordTabNumber * 16 * 20);
        // 基础段落样式
        return [
            'lineHeight' => self::$wordLineHeight,
            'align' => self::$wordTextAlign,
            'indentation' => ['firstLine' => $Indent_m->getFirstLine()]
        ];
    }

    /**
     * 执行导出文件
     * @param $fname
     * @return void
     */
    private static function outPut($fname): void
    {
        $name = $fname . ".docx"; //文件名称
        self::$phpWord->save($name, "Word2007", true);
    }
}